/** 
 * try to switched to task1 by ecall.
 * hzheng, 2023.08.16
 */

int printf_(const char* format, ...);

void mydelay(void);

#define GPIO_ODR *((volatile unsigned int *)0x50006000)

#define UART0_DR *((volatile unsigned int *)0x40008000)
#define UART0_FR *((volatile unsigned int *)0x40008018)
#define UART0_IBRD *((volatile unsigned int *)0x40008024)
#define UART0_FBRD *((volatile unsigned int *)0x40008028)
#define UART0_LCR_H *((volatile unsigned int *)0x4000802c)
#define UART0_CR *((volatile unsigned int *)0x40008030)

unsigned int gValue=0x30;

void invokeEcall(unsigned int argA0, unsigned int argA1){
  __asm__ __volatile__("ecall");
}

__attribute__((aligned(4))) void task1(void){
  while(1) {
    GPIO_ODR ^= 0x04;    
    mydelay();
  }  
}

void main() {
  
  unsigned int i;
  GPIO_ODR = 0x00;   
  //
  //init uart0
  //baudrate=115200, 115200=fclk/(16*n)
  //fclk = 80M or 160M
  //n1=80M/16/115200=43.40278; 0.40278*64+0.5=26
  //n2=160M/16/115200=86.80556; 0.80556*64+0.5=52
  UART0_CR = 0;
  UART0_LCR_H = 0x0060; //bit[6:5]=11
  UART0_IBRD = 43;
  UART0_FBRD = 26;
  UART0_CR = 0x0301; //txen, rxen, uarten
  
  printf_("start...\n");
  
  invokeEcall(1, (unsigned int)task1);
  
  //failed
  while(1) {
    GPIO_ODR = 0x00;   
    mydelay();
  }
}

void mydelay(void) {
  unsigned int i;
  for (i=0;i<10000000;i++) {
    __asm__ __volatile__("nop");
  }
}

void _putchar(char character) {
  //wait for tx fifo not full
  while (UART0_FR&(0x1<<5)) { //tx fifo full flag
    __asm__ __volatile__("nop");
  }
  UART0_DR = character;

}

/**
 * actual isr
 */
void myisr(void) {
  volatile unsigned int mcause;
  volatile unsigned int mepc;
  volatile unsigned int mtval;
  volatile unsigned int regA0;
  volatile unsigned int regA1;
  
  __asm__ __volatile__("mv %0, a0":"=r"(regA0));
  __asm__ __volatile__("mv %0, a1":"=r"(regA1));  
  __asm__ __volatile__("csrr %0, mcause":"=r"(mcause));
  
  if (mcause == 11) { //m ecall
    GPIO_ODR ^= 0x04;

    if (regA0 == 1) {
      mepc = regA1;
    }else {
      __asm__ __volatile__("csrr %0, mepc":"=r"(mepc));
      mepc = mepc + 4;
    }    
    __asm__ __volatile__("csrw mepc, %0":"=r"(mepc));
  }else {
    printf_("unexpected mcause: 0x%x.\n", mcause);
    __asm__ __volatile__("csrr %0, mtval":"=r"(mtval));
    printf_("mtval: 0x%x, halt!\n", mtval);
    while(1) {
    }  
  }
}
